/**
 * Copyright (c) Software Institute of PKU
 * All rights reserved. 
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 */
package edu.pku.sei.modeler.uml.internal;

import java.util.List;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;

import edu.pku.sei.modeler.exceptions.FactoryNotFoundException;
import edu.pku.sei.modeler.exceptions.PackageNotFoundException;
import edu.pku.sei.modeler.exceptions.ProjectLoadingException;
import edu.pku.sei.modeler.exceptions.ProjectSavingException;
import edu.pku.sei.modeler.model.common.AbstractFactory;
import edu.pku.sei.modeler.model.common.AbstractPackage;
import edu.pku.sei.modeler.model.common.ModelRegistry;
import edu.pku.sei.modeler.model.core.MetaModel;
import edu.pku.sei.modeler.model.core.MetaPackage;
import edu.pku.sei.modeler.model.structure.MetaDiagram;
import edu.pku.sei.modeler.model.structure.StructurePackage;
import edu.pku.sei.modeler.model.xml.XMLSaveLoader;
import edu.pku.sei.modeler.model.xml.XMLUtility;
import edu.pku.sei.modeler.project.AbstractModelingProject;
import edu.pku.sei.modeler.ui.editors.GraphicalEditorContextMenuProvider;
import edu.pku.sei.modeler.ui.editors.MetaModelEditor;
import edu.pku.sei.modeler.ui.editors.MetaModelEditorInput;
import edu.pku.sei.modeler.uml.UMLModelEditpartFactory;
import edu.pku.sei.modeler.uml.UMLModelTreeEditpartFactory;
import edu.pku.sei.modeler.uml.modelHelper.ModelFactory;
import edu.pku.sei.modeler.uml.modelHelper.ModelPackage;

/**
 * @generated
 * 
 */
public class GeneratedProject extends AbstractModelingProject {
	private GeneratedModelRoot modelRoot;

	public static String PROJECT_NATURE = "edu.pku.sei.modeler.uml";

	public GeneratedProject(IProject project, UMLModel model) {
		super();
		this.project = project;
		this.modelRoot = new GeneratedModelRoot();
		if (model == null) {
			modelRoot.initModel("defaultModel");
		} else {
			modelRoot.setModel(model);
		}
	}

	public MetaModel getModel() {
		return modelRoot.model;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.core.resources.IProjectNature#configure()
	 */
	public void configure() throws CoreException {
		// TODO Auto-generated method stub

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.core.resources.IProjectNature#deconfigure()
	 */
	public void deconfigure() throws CoreException {
		// TODO Auto-generated method stub

	}

	protected IWorkspace getWorkspace() {
		return ResourcesPlugin.getWorkspace();
	}

	public boolean hasDiagram(Object diagram) {
		return modelRoot.hasDiagram(diagram);
	}

	/**
	 * open an editor for the given diagram. if it is already open, bring it to
	 * top
	 * 
	 * @param diagram
	 *            20:14:27
	 */
	@SuppressWarnings("unchecked")
	public void openDiagram(Object diagram) {
		if (!(diagram instanceof MetaDiagram))
			return;
		Object obj = diagramEditorMap.get(diagram);
		MetaModelEditorInput input = null;
		//UMLModelEditorInput input = null;
		if (obj != null) {
			input = (MetaModelEditorInput) obj;
			//input = (UMLModelEditorInput)obj;
		} else {
			UMLModelEditpartFactory partFactory = new UMLModelEditpartFactory();
			UMLModelTreeEditpartFactory treeFactory = new UMLModelTreeEditpartFactory();
			input = new MetaModelEditorInput(partFactory, treeFactory);
			//input = new UMLModelEditorInput(partFactory, treeFactory);
			
			GeneratedPaletteFactory pFactory = GeneratedPaletteFactory.getDefault(modelRoot.model);
			input.setPaletteFactory(pFactory);
			input.setDiagram((MetaDiagram) diagram);
			
			
			input.setName(((MetaDiagram) diagram).getName());
			input.setProject(this);
			diagramEditorMap.put(diagram, input);
		}
		String editorID = input.editID;
		if (editorID == null)
			return;

		IWorkbench wb = PlatformUI.getWorkbench();
		IWorkbenchWindow win = wb.getActiveWorkbenchWindow();
		IWorkbenchPage page = win.getActivePage();

		IEditorPart editor = page.findEditor(input);
		if (editor != null) {
			page.bringToTop(editor);
		} else {
			try {
				editor = page.openEditor(input, editorID);
			} catch (PartInitException exception) {
				exception.printStackTrace();
			}
		}
		
		if(editor instanceof MetaModelEditor) {
			MetaModelEditor mEditor = (MetaModelEditor)editor;
//			mEditor.getGraphicalViewer().setContextMenu(
//					new UMLModelContextMenuProvider(
//							mEditor));
			mEditor.getGraphicalViewer().setContextMenu(new GraphicalEditorContextMenuProvider(mEditor.getGraphicalViewer(), diagram, mEditor.getActionRegistry()));
		}
		
		
		/*
		 * if(editor instanceof MetaModelEditor) { MetaModelEditor mEditor =
		 * (MetaModelEditor)editor; mEditor.getGraphicalViewer().setContextMenu(
		 * new ModelContextMenuProvider( mEditor.getGraphicalViewer(),
		 * mEditor.getActionRegistry())); }
		 */
	}

	// added by zhaoyi
	public void closeDiagram(Object diagram, boolean save) {
		Object obj = diagramEditorMap.get(diagram);
		MetaModelEditorInput input = null;
		if (obj != null) {
			input = (MetaModelEditorInput) obj;
		} else
			return;
		String editorID = input.editID;
		if (editorID == null)
			return;
		IWorkbench wb = PlatformUI.getWorkbench();
		IWorkbenchWindow win = wb.getActiveWorkbenchWindow();
		IWorkbenchPage page = win.getActivePage();
		IEditorPart editor = page.findEditor(input);
		if (editor != null) {
			page.closeEditor(editor, save);
		} else
			return;
	}

	@SuppressWarnings("unchecked")
	public IEditorPart getEditorbyDiagram(MetaDiagram diagram) {
		Object obj = diagramEditorMap.get(diagram);
		MetaModelEditorInput input = null;
		if (obj != null) {
			input = (MetaModelEditorInput) obj;
		} else {
			UMLModelEditpartFactory partFactory = new UMLModelEditpartFactory();
			UMLModelTreeEditpartFactory treeFactory = new UMLModelTreeEditpartFactory();
			input = new MetaModelEditorInput(partFactory, treeFactory);
			input.setDiagram((MetaDiagram) diagram);
			input.setName(((MetaDiagram) diagram).getName());
			diagramEditorMap.put(diagram, input);
		}
		String editorID = input.editID;
		if (editorID == null)
			return null;
		IWorkbench wb = PlatformUI.getWorkbench();
		IWorkbenchWindow win = wb.getActiveWorkbenchWindow();
		IWorkbenchPage page = win.getActivePage();

		IEditorPart editor = page.findEditor(input);


		if (editor != null) {
			page.bringToTop(editor);
		} else {
			try {
				page.openEditor(input, editorID);
			} catch (PartInitException exception) {
				exception.printStackTrace();
			}
		}
		return editor;
	}

	public void saveProject() throws ProjectSavingException {
		if (project == null)
			return;

		IFile mFile = createProjectFile(modelFile);
		IFile dFile = createProjectFile(diagramFile);
		createProjectFile(notationFile);

		try {
			ModelFactory factory = (ModelFactory) ModelRegistry.getRegistry().getFactory(modelRoot.model);
			AbstractFactory sFactory = ModelRegistry.getRegistry().getStructureFactory(modelRoot.model);

			AbstractPackage pkg = ModelRegistry.getRegistry().getPackageByFactory(factory);
			XMLUtility.xmlInstance.resetUtility();
			XMLSaveLoader sl = new XMLSaveLoader(factory, pkg);

			// prepare factories
			sl.addModelFactory(factory);
			sl.addModelFactory(sFactory);

			// save model
			sl.setModel(modelRoot.getModel());
			sl.save(mFile.getLocation().toOSString(), ModelPackage.__METAMODEL__);
			// save diagrams
			List diagrams = modelRoot.model.getInstancesForType(StructurePackage.__DIAGRAM__);
			sl.setModel(diagrams);
			sl.save(dFile.getLocation().toOSString(), StructurePackage.__DIAGRAM__);
			// save notation
			/*
			 * if(modelRoot.model instanceof CoreMetaModel) { AbstractFactory
			 * nFactory =
			 * ModelRegistry.getRegistry().getNotationFactory(modelRoot.model);
			 * List notations = ((CoreMetaModel)modelRoot.model).getNotations();
			 * sl.setModelPackage(ModelRegistry.getRegistry().getNotationPkgByModel(modelRoot.model));
			 * sl.addModelFactory(nFactory); sl.setModel(notations);
			 * sl.save(nFile.getLocation().toOSString(),
			 * NotationPackage.TYPE_NOTATION); }
			 */
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (FactoryNotFoundException e) {
			e.printStackTrace();
		} catch (PackageNotFoundException e) {
			e.printStackTrace();
		}
	}

	private IFile createProjectFile(String projectFile) throws ProjectSavingException {
		IFile file = project.getFile(projectFile);
		if (!file.exists()) {
			try {
				file.create(null, IResource.NONE, null);
			} catch (CoreException e) {
				throw new ProjectSavingException("failed to create file:" + projectFile);
			}
		}

		return file;
	}

	public void loadProject() throws ProjectLoadingException {
		if (project == null)
			throw new ProjectLoadingException("real project is NULL");
		if (modelRoot == null) {
			modelRoot = new GeneratedModelRoot();
		}
		if (modelRoot.model != null) {
			ModelRegistry.getRegistry().unRegisterModel(modelRoot.model);
		}
		try {
			String comment = project.getDescription().getComment();
			if (comment != null && !"".equals(comment)) {
				String modelName = comment.substring(comment.indexOf('=') + 1);
				this.modelFile = modelName + ".model";
				this.diagramFile = modelName + ".diagram";
				this.notationFile = modelName + ".notation";
			}
		} catch (Exception e) {
			throw new ProjectLoadingException("read project comment failed");
		}
		IFile file = project.getFile(modelFile);
		if (!file.exists()) {
			modelRoot.initModel("DefaultModel");
		} else {
			ModelFactory factory = new ModelFactory();
			ModelPackage pkg = new ModelPackage();
			XMLUtility.xmlInstance.resetUtility();
			XMLSaveLoader xmlSaveLoader = new XMLSaveLoader(factory, pkg);
			xmlSaveLoader.addModelFactory(factory);

			// load model
			xmlSaveLoader.load(file.getLocation().toOSString(), ModelPackage.__METAMODEL__);
			if (xmlSaveLoader.getModel() instanceof MetaModel) {
				modelRoot.setModel((UMLModel) xmlSaveLoader.getModel());
				ModelRegistry.getRegistry().registerModel(xmlSaveLoader.getModel(), factory, pkg);
			} else {
				throw new ProjectLoadingException("root element is not a MetaModel");
			}
			// load diagrams
			IFile dFile = project.getFile(diagramFile);
			if (dFile.exists()) {
				xmlSaveLoader.setModel(null);
				xmlSaveLoader.load(dFile.getLocation().toOSString(), StructurePackage.__DIAGRAM__);
				if (xmlSaveLoader.getModel() instanceof List) {
					List diags = (List) xmlSaveLoader.getModel();
					for (int i = 0; i < diags.size(); i++) {
						if (diags.get(i) instanceof MetaDiagram) {
							MetaDiagram diag = (MetaDiagram) diags.get(i);
							if (diag.getContainer() instanceof MetaPackage) {
								((MetaPackage) diag.getContainer()).getDiagrams().add(diag);
							}
						}
					}
				} else if (xmlSaveLoader.getModel() instanceof MetaDiagram) {
					MetaDiagram diag = (MetaDiagram) xmlSaveLoader.getModel();
					if (diag.getContainer() instanceof MetaPackage) {
						((MetaPackage) diag.getContainer()).getDiagrams().add(diag);
					}
				}
			}
		}
	}
}
